home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 37
/
Amiga Format CD37 (1999-02-16)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-03].iso
/
-screenplay-
/
shareware
/
invasionforce
/
source
/
sound2.cx
< prev
next >
Wrap
Text File
|
1999-01-09
|
18KB
|
576 lines
/**************************** Sound.c *********************************
Sound is copyright (c) 1988 by Richard Lee Stockton, 21305 60th Ave W.,
Mountlake Terrace, Washington 98043, 206/776-1253(voice), but may be freely
distributed as long as no profit is made from its distribution or sale
without my written permission. I call this concept 'FreeWare', you can
call it whatcha want.
I also include the source code, (Manx Aztec 5.0d), in the hope that it
will be of benefit to someone in the Amiga programming community. Feel free
to alter it at will, (but at your own risk!). I _would_ appreciate
receiving a copy of whatever it may become and it is always nice to receive
credit, (perhaps just a few lines of glowing tribute.^)
Long Live Leo and All the Little Schwabies!
To Manufacture with Manx 5.0d
cc -ps -safnps Sound.c
ln +cdb Sound.o -lc16
**************************************************************************/
#include <exec/memory.h>
//#include <workbench/startup.h>
//#include <workbench/workbench.h>
//#include <workbench/icon.h>
//#include <libraries/dosextens.h>
//#include <graphics/gfxbase.h>
#include <devices/audio.h>
#include <string.h>
#include <functions.h>
#include "sound2_protos.h"
/* Less than WorkBench 1.2 need not apply. That's nobody, right? ;-> */
#define REVISION 33L
/* We'll need 4 buffers in CHIP memory, all else in FAST, if ya got it */
long BUFSIZE = 1024L;
/* A pretty little HELP message showing valid variable ranges */
//#define USAGE "\
//\033[42m\033[31m\
// USAGE: Sound <file> [56-65535] [v1-v64] [0-55] [e1-e64] [dfglrsq] \
//\033[m\n\033[42m\
// ABORT: <CTRL> 'c'\033[33m\
// SAMPLES/SEC VOLUME CYCLES END_VOL FLAGS \
//\033[m\n\033[42m\033[31m\
// GRAMMA SOFTWARE * freely distributable * 07 Mar \xA9 1991 RLStockton \
//\033[m\n"
/* Probably more GLOBALS than are required. 'C' is funny stuff. */
//extern struct GfxBase *GfxBase=NULL;
//extern struct IconBase *IconBase=NULL;
//extern struct IntuitionBase *IntuitionBase=NULL;
//extern struct MsgPort *CreatePort();
//extern struct WBStartup *WBenchMsg=NULL;
//extern struct WBArg *argp=NULL;
// struct IntuiMessage *message=NULL;
// struct Window *StatusWindo=NULL;
struct DiskObject *infofile=NULL;
struct IOAudio *sound[4]={NULL,NULL,NULL,NULL};
struct Filehandle *sFile=NULL;
struct FileLock *lock=NULL, *savelock=NULL;
long sactual=0L, sstart=0L, vol=64L, fade=0L,
atol(), sps=0L, cycles=1L, startvol=64L,
endvol=64L, fadevol=0L;
short k=0, stereo=0, left=1, right=1, compflag=0,
statusline=1, direct=0;
UBYTE sunit[4]={12,10,5,3},
sunitL[2]={1,8}, sunitR[2]={2,4};
BOOL help=FALSE;
char *sbuffer=NULL, *ltoa(), title[108]="",
*cbuf[4]={NULL,NULL,NULL,NULL},
sname[108], *SafeAllocMem(),
*portname[4]={"Snd0","Snd1","Snd2","Snd3"},
comptable[16]={-34,-21,-13,-8,-5,-3,-2,-1,
0,1,2,3,5,8,13,21};
void loadSound(), setStatusWindo(),
soundSound(), cleanup(), snd_quit();
short svol=64;
/*********** quit, give-up, go home, finish... Neatness counts! ******/
void snd_quit(qstring)
char *qstring;
{
cleanup(qstring);
return;
}
void cleanup(string)
char *string;
{
if(sound[0]) /* This cleans up the audio device stuff */
{
for(k=3;k>(-1);k--)
{
if((sound[k])&&(sound[k]->ioa_Request.io_Device))
AbortIO((struct IORequest *)sound[k]);
}
if(sound[0]->ioa_Request.io_Device)
CloseDevice((struct IORequest *)sound[0]);
for(k=3;k>(-1);k--)
{
if(sound[k]->ioa_Request.io_Message.mn_ReplyPort)
DeletePort(sound[k]->ioa_Request.io_Message.mn_ReplyPort);
}
for(k=3;k>(-1);k--)
{
if(sound[k])
FreeMem(sound[k],(long)sizeof(struct IOAudio));
if(cbuf[k])
FreeMem(cbuf[k],BUFSIZE);
}
sound[0]=sound[1]=sound[2]=NULL;
}
/* Write any message to out. May be error or could be samples/second */
/* You'll be sorry if you try to Write(Output()) to WorkBench! 8-) */
// if(help) Write(Output(),string,(long)strlen(string));
// else if(strlen(string)>10L)
// {
// strcpy(title,"Sound Error: "); strcat(title,string);
// setStatusWindo(); Delay(128L); sound[3]=NULL;
// }
/* Clean up everything else */
// if(StatusWindo) CloseWindow(StatusWindo);
// if(IntuitionBase) CloseLibrary(IntuitionBase);
if(sFile) Close((BPTR)sFile);
if(sbuffer) FreeMem(sbuffer,sactual);
if(infofile) FreeDiskObject(infofile);
// if(IconBase) CloseLibrary(IconBase);
if(!sound[3]) snd_quit(NULL);
/* Reset everything in case we are returning (WB multiple select) */
// StatusWindo=NULL; // IntuitionBase=NULL;
sbuffer=NULL; infofile=NULL;
sactual=0L; sstart=0L; savelock=NULL; sps=0L; cycles=1L;
lock=0L; k=0; stereo=0; left=1; right=1; startvol=endvol=vol=64L;
}
void doSound(effect,loud)
short loud;
char *effect;
{
svol = loud;
loadSound(effect);
soundSound();
snd_quit(effect);
}
/* Don't Allocate if Low Mem - by Bryce Nesbitt */
/* Aberations by RLS. 4096 should be fudge enough */
char *SafeAllocMem(size,flags)
long size, flags;
{
register char *p;
if(p=(char *)AllocMem(size,flags))
if(AvailMem(MEMF_CHIP)<4096L) {FreeMem(p,size); return(NULL);}
return(p);
}
/* This routine de-compresses Fibonacci Delta data, 1 byte at a time */
/* x is the top nibble, y is the bottom. You get 2, 2, 2 bytes from one! */
short decomp(sbuff,i,j,zz)
char *sbuff;
long i,j;
short zz;
{
short x,y;
x=((sbuff[i])>>4)&15; y=(sbuff[i])&15;
sbuff[j]=comptable[x]+zz; zz=sbuff[j];
sbuff[j+1L]=comptable[y]+zz; return(sbuff[j+1L]);
}
/******** Load SoundFile 'sPath' & set cycles-sps-stereo *******/
void loadSound(sPa)
char *sPa;
{
struct FileInfoBlock *finfo=NULL;
struct FileLock *lock=NULL;
long i, j;
char string[5], sPath[80];
short z;
/* Allocate 256 bytes as work memory */
strcpy(sPath,sPa);
if(!(sbuffer=SafeAllocMem(256L,MEMF_CLEAR|MEMF_PUBLIC)))
snd_quit("No Work Memory!");
/* Check for and parse IFF data in first 256 bytes of file */
if(!(sFile=(struct Filehandle *)Open(sPath,MODE_OLDFILE)))
{
sactual=256L; snd_quit("Can't Find SoundFile!");
}
Read((BPTR)sFile,sbuffer,256L); /* load the 1st 256 bytes */
for(sstart=0L, sps=0L, i=0L; i<252L; i+=4L)
{
strncpy(string,sbuffer+i,4); string[4]=NULL;
if(!(strcmp(string,"VHDR"))) /* get samples per second */
{
for(j=0L;j<(long)((UBYTE)sbuffer[i+20]);j++) sps+=256L;
sps += (long)((UBYTE)sbuffer[i+21L]);
if(sbuffer[i+23L]==1) compflag=1;
if(sbuffer[i+27L]!=1)
startvol=(64L*(long)(sbuffer[i+28L]*10+sbuffer[i+29L]))/100L;
}
if(!(strcmp(string,"CHAN"))) /* Channel Assignment */
{
if((sbuffer[i+7L]==6)||(sbuffer[i+11L]==6)) stereo=1;
}
if(!(strcmp(string,"BODY"))) /* get size of sound data */
{
for(j=0L;j<4L;j++)
sactual+=((long)((UBYTE)sbuffer[i+7L-j])<<(8*j));
sstart = i+8L; i=252L;
}
}
/* if not in IFF format, get filesize from FileInfoBlock */
if(!sactual)
{
/* Allocate a file info block, get size from it, and de-allocate */
if((!(finfo=(struct FileInfoBlock *)
SafeAllocMem((long)sizeof(struct FileInfoBlock),MEMF_CLEAR)))
||(!(lock=(struct FileLock *)Lock(sname,ACCESS_READ)))
||(!(Examine((BPTR)lock,finfo))) )
snd_quit("FileInfoBlock Problem!");
sactual = finfo->fib_Size; if(lock) UnLock((BPTR)lock);
if(finfo) FreeMem(finfo,(long)sizeof(struct FileInfoBlock));
}
/* clean up work area */
FreeMem(sbuffer,256L); sbuffer=NULL;
if(compflag) sactual=sactual*2L;
/* Allocate memory for SOUND data. */
/* Later we'll transfer in BUFSIZE chunks to contiguous CHIP memory. */
if(AvailMem(MEMF_LARGEST)<(sactual+16384L)) direct=1;
if(direct) return;
if(!(sbuffer=SafeAllocMem(sactual,MEMF_CLEAR|MEMF_PUBLIC)))
snd_quit("Memory Allocation Failed!");
/* Load the data into sbuffer */
Seek((BPTR)sFile,sstart,OFFSET_BEGINNING);
if((Read((BPTR)sFile,sbuffer,sactual)) == -1L) snd_quit("Read Error!");
Close((BPTR)sFile); sFile=NULL;
/* decompression */
if(compflag)
{
// if(statusline)
// {
// strcpy(title,"Processing Fibonacci Delta Compression");
// setStatusWindo();
// }
if(stereo)
{
memcpy(sbuffer+(3L*sactual)/4L,sbuffer+(sactual/4L),sactual/4L);
memcpy(sbuffer+(sactual/4L),sbuffer,sactual/4L);
j=1L; sbuffer[0]=sbuffer[j]; z=sbuffer[j];
for(i=sactual/4L+2L;i<(sactual/2L);i++,j+=2L)
z=decomp(sbuffer,i,j,z);
j=sactual/2L; sbuffer[j]=sbuffer[(3L*sactual)/4L+1L];
z=sbuffer[j]; j++;
for(i=(3L*sactual)/4L+2L;i<sactual;i++,j+=2L)
z=decomp(sbuffer,i,j,z);
}
else
{
memcpy(sbuffer+(sactual/2L),sbuffer,sactual/2L);
/* 1st byte is pad, 2nd byte is 1st value. FOR EACH STEREO SIDE! */
for(i=sactual/2L+2L,j=1L,z=sbuffer[1];i<sactual;i++,j+=2L)
z=decomp(sbuffer,i,j,z);
}
}
}
/***************** make a noise ******************/
void soundSound()
{
//ULONG class;
LONG i, j, dactual, dlength, remaining;
USHORT count;
short z;
/* Make sure we have valid values before 'sounding' */
if(left==right) left=right=1;
if((sps<56L)||(sps>65534L)) sps=10000L;
if((startvol<1L)||(startvol>64L)) startvol=64L;
vol=svol;
//vol=startvol;
if((endvol<1L)||(endvol>64L)) endvol=64L;
if(direct)
{
BUFSIZE=AvailMem(MEMF_CHIP|MEMF_LARGEST)/6L;
if(BUFSIZE>64000L) BUFSIZE=64000L;
BUFSIZE-=(BUFSIZE%8L);
}
/* cycles<56 limit only applies to CLI */
if((cycles<0L)||(cycles>65535L)) cycles=1L;
if(cycles>1L) fadevol=(endvol-startvol)/(cycles-1L);
else fadevol=0L;
/* Put up a 'status' window on the top line. */
// if(statusline) {maketitle(); setStatusWindo();}
/* Allocate sound data buffers from CHIP memory. Ports and */
/* Audio Request Structures do NOT require CHIP memory */
for(k=0;k<4;k++)
{
if(!(cbuf[k]=SafeAllocMem(BUFSIZE,
MEMF_CHIP|MEMF_CLEAR|MEMF_PUBLIC))) snd_quit("No CHIP Memory!");
if(!(sound[k]=(struct IOAudio *)SafeAllocMem((long)sizeof(struct IOAudio),
MEMF_CLEAR|MEMF_PUBLIC))) snd_quit("No IOA Memory!");
if(!(sound[k]->ioa_Request.io_Message.mn_ReplyPort =
CreatePort(portname[k],0L))) snd_quit("No Port Memory!");
}
/* Open Audio using the first IOAudio as the 'initializer' request */
sound[0]->ioa_Request.io_Message.mn_Node.ln_Pri = 114;
if(!right) sound[0]->ioa_Data = &sunitL[0];
else if(!left) sound[0]->ioa_Data = &sunitR[0];
else sound[0]->ioa_Data = &sunit[0];
sound[0]->ioa_Length = 4L;
if((OpenDevice(AUDIONAME,0L,(struct IORequest *)sound[0],0L))!=NULL)
{
sound[0]->ioa_Request.io_Device=NULL; /* don't AbortIO if no open */
snd_quit("No Audio Device!");
}
/* Set all IOAudios. */
for(k=0;k<4;k++)
{
sound[k]->ioa_Request.io_Message.mn_Node.ln_Pri = 114;
sound[k]->ioa_Request.io_Command = CMD_WRITE;
sound[k]->ioa_Request.io_Flags = ADIOF_PERVOL;
/* Note copies of Device & AllocKey from initializer. */
sound[k]->ioa_Request.io_Device = sound[0]->ioa_Request.io_Device;
sound[k]->ioa_AllocKey = sound[0]->ioa_AllocKey;
/* Each IOAudio has its own CHIP buffer, Port, and Unit (left/right) */
sound[k]->ioa_Data = (UBYTE *)cbuf[k];
/* 3579547 divided by 55 = 65083, nearly the maximum Period (65535) */
/* changing this 'magic' number is all we need to make it 'European' */
// if(GfxBase->DisplayFlags&PAL) sound[k]->ioa_Period=3546895L/sps;
sound[k]->ioa_Period=3579547L/sps;
/* allow for volume setting. gives us effect possibilities in a script */
sound[k]->ioa_Volume = startvol;
/* One time through this BUFSIZE (or smaller) part of the whole */
sound[k]->ioa_Cycles = 1L;
}
/* The compiler wants 'Unit' to be a structure, we just want to mask */
/* into the allocated left/right channels. left=1 or 8, right=2 or 4 */
/* ...zap! You're a Unit structure! Feel any different? */
for(k=2;k>(-1);k-=2)
{
if(right) sound[k+1]->ioa_Request.io_Unit = (struct Unit *)
((ULONG)(sound[0]->ioa_Request.io_Unit)&6L);
if(left) sound[k]->ioa_Request.io_Unit = (struct Unit *)
((ULONG)(sound[0]->ioa_Request.io_Unit)&9L);
}
/* If in STEREO, split file. If in MONO, 'b' buffers use 'a' data */
if(stereo) remaining=(sactual/2L)-(sactual&1L);
else
{
remaining=sactual;
sound[1]->ioa_Data = (UBYTE *)cbuf[0];
sound[3]->ioa_Data = (UBYTE *)cbuf[2];
}
/* dactual is the length of one channel's complete data */
dactual=remaining; k=count=0;
/* if DIRECT_FROM_DISK, start at the beginning of the sample */
if(direct) Seek((BPTR)sFile,sstart,OFFSET_BEGINNING);
/* we be doing loops here */
do
{
/* be CERTAIN ioa_Length is an even number & set datalength */
if(remaining>BUFSIZE) dlength=BUFSIZE;
else {dlength=remaining; dlength-=(dlength&1L);}
/* Move the data into the proper CHIP buffer of BUFSIZE */
if(direct)
{
if(stereo) Seek((BPTR)sFile,sstart+dactual-remaining,
OFFSET_BEGINNING);
if(compflag)
{
Read((BPTR)sFile,cbuf[k]+dlength/2L,dlength/2L);
if(remaining==dactual)
{z=cbuf[k][1L+dlength/2L]; cbuf[k][0]=z; i=2L; j=1L;}
else {i=0L; j=0L;}
for(;i<(dlength/2L);i++,j+=2L)
z=decomp(cbuf[k],i+dlength/2L,j,z);
}
else Read((BPTR)sFile,cbuf[k],dlength);
}
else movmem(sbuffer+(dactual-remaining),cbuf[k],(int)dlength);
/* Don't load or use the right CHIP buffers if MONO. Saves time. */
if(stereo)
{
if(direct)
{
if(compflag)
{
Seek((BPTR)sFile,sstart+dactual+dactual/2L-remaining,
OFFSET_BEGINNING);
Read((BPTR)sFile,cbuf[k+1]+dlength/2L,dlength/2L);
if(remaining==dactual)
{z=cbuf[k+1][1L+dlength/2L]; cbuf[k+1][0]=z; i=2L; j=1L;}
else {i=0L; j=0L;}
for(;i<(dlength/2L);i++,j+=2L)
z=decomp(cbuf[k+1],i+dlength/2L,j,z);
}
else
{
Seek((BPTR)sFile,sstart+sactual-remaining,OFFSET_BEGINNING);
Read((BPTR)sFile,cbuf[k+1],dlength);
}
}
else movmem(sbuffer+(sactual-remaining),cbuf[k+1],(int)dlength);
}
/* Data has been moved, so adjust 'remaining' */
remaining-=dlength;
/* Left and Right Lengths are the same, no matter what! */
sound[k]->ioa_Length = sound[k+1]->ioa_Length = dlength;
/* Start one set of Left/Right Channels. */
if(left) BeginIO((struct IORequest *)sound[k]);
if(right) BeginIO((struct IORequest *)sound[k+1]);
/* If no QUIET flag, Check Intuition for the ABORT message */
// if(statusline)
// {
// while(message=(struct IntuiMessage *)GetMsg(StatusWindo->UserPort))
// {
// class = message->Class; code = message->Code;
/* Hi Intuition! Thanks for the message, Have a nice day! */
// ReplyMsg((struct Message *)message);
/* <CTRL> 'c' abort. 1,2,3, easy as a,b,c, baby you and me! */
// if((class==VANILLAKEY)&&(code==3)) snd_quit("");
// }
// }
if(fade!=0L)
{vol=(64L*remaining)/dactual; if(fade>0L) vol=64L-vol;}
/* Is this the last time AND the last cycle? If yes & no, reset. */
if(remaining<2L)
{
cycles--;
if(cycles!=0L)
{
if(direct) Seek((BPTR)sFile,sstart,OFFSET_BEGINNING);
remaining=dactual; dlength=BUFSIZE;
if(fadevol!=0L)
{
vol=vol+fadevol;
// if(statusline) {maketitle(); setStatusWindo();}
}
}
}
if(vol>64L) vol=64L; if(vol<1L) vol=1L;
for(i=0L;(i<4L)&&(vol>=0L);i++) sound[i]->ioa_Volume = vol;
/* Is this the last time, or what? */
if(remaining<2L)
WaitIO((struct IORequest *)sound[k+right]); /* wait for LAST request */
else
{
if(k) k=0; else k=2; /* switch buffers & wait for PREVIOUS */
if(count++) WaitIO((struct IORequest *)sound[k+right]);
}
/* Keep going until we run out of data */
} while(remaining>1L); /* End of Loop */
}
/********** long int to char string (up to 10 digits) ***********/
char *ltoa(num)
long num;
{
static char ostring[11]="";
short next = 10, shift = 0;
if (!num) ostring[next--] = '0';
while ((num+9L)/10)
{ ostring[next--] = num % 10L + '0'; num /= 10L; }
next+=1;
while(next<11) ostring[shift++] = ostring[next++];
while(shift<11) ostring[shift++] = '\0';
return(ostring);
}
/************************** end of Sound.c ******************************/